/**
 * Copyright 2008 Matthew DeLambo
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.delambo.drool.logging;

import com.delambo.drool.exceptions.DroolException;
import com.delambo.drool.utilities.*;
import com.delambo.drool.interfaces.*;
import java.io.*;
import java.util.*;
import javax.mail.*;
import javax.mail.internet.*;
import java.net.*;

/**
 * Singleton class that spins off logging threads for different levels of 
 * logging: Development and Production.
 * @author delambo
 */
public final class Logger_Impl implements com.delambo.drool.interfaces.Logger {
    private DataOutputStream dout;
    private Session session;
    private int logLevel;
    private String newline;
    private boolean mailSomeone;
    private ArrayList mailRecipient;
    private String mailingFrom, logFile, mailHost;
    private final int PROD = 2, DEV = 1, OFF = 0;
    
    public Logger_Impl() {}
    
    /**
     * Initializes a logger with properties.
     * @param props property set.
     */
    public void init(PropertyMap props) {
        logFile = (String) props.getProperty("LOG_FILE");
        logLevel = (Integer) props.getProperty("LOGGING_LEVEL");
        newline = (String) props.getProperty("NEWLINE");
        mailSomeone = (Boolean) props.getProperty("MAIL_SOMEONE");
        mailRecipient = (ArrayList) props.getProperty("MAIL_RECIPIENTS");
        mailingFrom = (String) props.getProperty("MAILING_FROM");
        mailHost = (String) props.getProperty("MAIL_HOST");
        setupLogFile();
        setupMailSystem();
    }
    
    /**
     * Checks and spins a development logging thread.
     * @param msg logging message.
     * @param ex java exception.
     */
    public void dev(String msg, Exception ex) {
        if(logLevel == DEV)
            startNewLoggingThread("DEV", msg, ex);
    }
    
    /**
     * Checks and spins a production logging thread.
     * @param msg logging message.
     * @param ex java exception.
     */
    public void prod(String msg, Exception ex) {
        if(logLevel == PROD)
            startNewLoggingThread("PROD", msg, ex);
    }
    
    /**
     * Checks and spins a logging thread.
     * @param msg logging message.
     * @param ex java exception.
     */
    public void all(String msg, Exception ex) {
        if(logLevel != OFF)
            startNewLoggingThread("ALL", msg, ex);
    }

    /**
     * Shuts down the output stream for this logger.
     */
    public void shutDown() {
        if (dout != null) {
            try {
                dout.close();
            } catch (IOException e) {
                System.out.println("IOException in shutdown(): " + e);
            }
        } else {
            System.out.println(
                    "Error: Could not close log file output in shutdown()");
        }
    }
    
    /**
     * Runs a new thread to output to the log.
     * @param logType type of log message.
     * @param msg log message.
     * @param ex java exception.
     */
    private void startNewLoggingThread(final String logType, 
            final String msg, final Exception ex) {
        if(dout == null)
            return;
        new Thread (new Runnable() { 
            public void run() {
                logIt(logType, msg, ex);
            }
        }).start(); 
    }
    
    /**
     * Handles output for logging.
     * @param logType type of log message.
     * @param msg log message.
     * @param ex java exception.
     */
    private synchronized void logIt(String logType, String msg, 
            final Exception ex) {
        try {
            if(ex != null) {
                if(ex instanceof DroolException)
                    dout.writeBytes(newline + logType + " [" + new Date() + "]: "
                        + msg + newline + ((DroolException)ex).getTrace() +newline);
                else
                    dout.writeBytes(newline + logType + " [" + new Date() + "]: "
                        + msg + newline + getTrace(ex) + newline);
            }
            else
                dout.writeBytes(newline + logType + " [" + new Date() + "]: "
                        + msg + newline);
            if(mailSomeone) {
                String temp;
                for (int i = 0; i < mailRecipient.size(); i++) {
                    temp = (String) mailRecipient.get(i);
                    try {
                        MimeMessage message = new MimeMessage(session);
                        message.setFrom(new InternetAddress(mailingFrom));
                        message.addRecipient(Message.RecipientType.TO, new 
                                InternetAddress(temp));
                        message.setSubject("CONN POOL " + logType);
                        message.setText(logType + 
                                " [" + new Date() + "]: " + msg);
                        Transport.send(message);
                    } catch (AddressException e) {
                        System.out.println("Mail Address ex in logger: " + e);
                    } catch (MessagingException e) {
                        System.out.println("Messaging ex in logger: " + e);
                    }
                }
           }
        } catch (IOException e) {
            System.out.println("IOException logIt(): " + e);
        }

    }

    /**
     * Sets up mailing for this logger.
     */
    private void setupMailSystem() {
        String smtpHost = new String();
        try{
            InetAddress host = InetAddress.getLocalHost();         
            smtpHost = host.getHostName();
        }
        catch(UnknownHostException uhe){
            System.out.println("UnknownHostEx in setupMailSystem(): " + uhe);
        }        
        Properties props = System.getProperties();
        props.put("mail.smtp.host", mailHost);
        session = Session.getInstance(props, null);
    } 

    /**
     * Opens output stream to logfile.
     */
    private void setupLogFile() {
        try {
            dout = new DataOutputStream(new FileOutputStream(
                    new File(logFile), true));
        } catch (IOException e) {
            System.out.println("IOexception setupLogFile: " + e);
        }
    }
    
    /**
     * Returns the stacktrace of a java exception.
     * @param e java exception.
     * @return string of the incoming exceptions stacktrace.
     */
    private String getTrace(Exception e) {
        ByteArrayOutputStream b = new ByteArrayOutputStream();
        PrintStream p = new PrintStream(b);
        e.printStackTrace(p);
        p.flush();
        return b.toString();
    }
    
}

